package cn.haoma.base.img;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;

import javax.net.ssl.HttpsURLConnection;

/**
 * @author Hunter
 *         要处理解码图片过程中产生的OOM错误，需要调用registMemoryAlarm(MemoryListener listener);
 *         使用Img类之前需要先初始化FileUtil类
 *         需要文件读写权限和网络权限（不下载图片可以不要）
 */
public class Img {
    public static final short SIZE_MODE_BASE_ON_WIDTH = 1;
    public static final short SIZE_MODE_BASE_ON_HEIGHT = 2;
    public static final short SIZE_MODE_BASE_ON_EXACTLY_ARGS = 3;
    public static final short SIZE_MODE_BASE_ON_ORIGIN_SIZE = 4;
    private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private static PorterDuffXfermode duffXfermode;
    private String TAG = Img.class.getName();
    /**
     * 加载到内存中的Bitmap
     */
    private Bitmap bitmap;
    private File cacheDirectory;
    /**
     * 生成的缩略图的文件路径
     */
    private String cacheFilePath = "";
    /**
     * 图片本地的文件路径
     */
    private String filePath;
    /**
     * 解码出来的Bitmap的高度（单位像素）
     */
    private int height;
    private ImgListener imgListener;
    private boolean isSizeKnown;
    private int radius;
    private short sizeMode = SIZE_MODE_BASE_ON_ORIGIN_SIZE;
    /**
     * 图片的url请求地址
     */
    private String url;
    /**
     * 与之绑定的ImageView
     */
    private HashSet<View> viewSet;
    /**
     * 解码出来的Bitmap的宽度（单位像素）
     */
    private int width;

    public Img(File cacheDirectory, File fileDirecotry, String url) {
        this(cacheDirectory, fileDirecotry.getPath() + '/' + (url == null ? "null" : url.hashCode()) + ".jpg");
        this.url = null == url ? "" : url;
    }

    public Img(File cacheDirectory, String filePath) {
        this.filePath = filePath;
        this.cacheDirectory = cacheDirectory;
        this.viewSet = new HashSet<View>();
    }

    /**
     * 一个Img可以绑定多个view
     *
     * @param view
     */
    final public void bindView(View view) {
        viewSet.add(view);
    }

    public boolean decodeBitmap() throws IOException {
        if (isBitmapDecoded()) {
            return true;
        }
        getBitmapFromCache();
        if (null == bitmap) {
            if (fileExists()) {
                if (isSizeKnown || sizeMode == SIZE_MODE_BASE_ON_EXACTLY_ARGS) {
                    bitmap = ImgUtil.getBitmap(filePath, width, height);
                } else if (sizeMode == SIZE_MODE_BASE_ON_ORIGIN_SIZE) {
                    bitmap = ImgUtil.getBitmap(filePath);
                } else if (sizeMode == SIZE_MODE_BASE_ON_HEIGHT) {
                    bitmap = ImgUtil.getScaledBitmap(filePath, height);
                } else if (sizeMode == SIZE_MODE_BASE_ON_WIDTH) {
                    bitmap = ImgUtil.getScaledBitmap(width, filePath);
                }
                if (null != bitmap) {
                    if (radius != 0) {
                        bitmap = ImgUtil.getCircleBitmap(bitmap);
                    }
                    if (sizeMode != SIZE_MODE_BASE_ON_ORIGIN_SIZE) {
                        isSizeKnown = true;
                    }
                    width = bitmap.getWidth();
                    height = bitmap.getHeight();
                    saveCacheIfNecessary();
                }
            }

        }
        return null != bitmap;

    }

    public void decodeBitmapAsync(final Handler h) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (decodeBitmap()) {
                        h.sendEmptyMessage(0);
                    } else {
                        h.sendEmptyMessage(1);
                    }
                } catch (Exception e) {
                    h.sendEmptyMessage(1);
                }

            }
        }).start();
    }

    /**
     * 删除图片源文件及缓存
     */
    final public void deleteFile() {
        new File(filePath).delete();
        deleteCacheFile();
    }

    /**
     * 删除图片缓存
     */
    final public void deleteCacheFile() {
        new File(cacheFilePath).delete();
    }

    public boolean download() {
        String suffix = ".tmp";
        boolean isDownloaded = false;
        FileOutputStream fos = null;
        try {
            URL u = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) u.openConnection();
            connection.setReadTimeout(3000);
            connection.setDoInput(true);
            connection.setDoOutput(false);
            connection.setConnectTimeout(10000);
            InputStream is = connection.getInputStream();
            File tmpFile = new File(filePath + suffix);
            fos = new FileOutputStream(tmpFile);
            byte[] buffer = new byte[2048];
            int n = 0;
            do {
                Thread.yield();
                fos.write(buffer, 0, n);
                n = is.read(buffer);
            } while (n != -1);
            fos.close();
            tmpFile.renameTo(new File(filePath));
            isDownloaded = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (!isDownloaded) {
                new File(filePath + suffix).delete();
                Log.e(TAG, "Pic Download Failed ：URL = " + url);
            }
        }
        return isDownloaded;

    }

    public void downloadAndDecodeAsync(final Handler handler) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (new File(filePath).exists() || download()) {
                        if (decodeBitmap()) {
                            handler.sendEmptyMessage(0);
                        } else {
                            handler.sendEmptyMessage(1);
                        }
                    } else {
                        handler.sendEmptyMessage(1);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    handler.sendEmptyMessage(1);
                }
            }
        }).start();
    }

    /**
     * @param handler 0 下载成功， 1 URL格式不正确， 2 IO异常
     */
    public void downloadAsync(final Handler handler) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    URL u = new URL(url);
                    HttpsURLConnection connection = (HttpsURLConnection) u.openConnection();
                    FileOutputStream fos = new FileOutputStream(filePath);
                    InputStream is = connection.getInputStream();
                    byte[] buffer = new byte[2048];
                    int n = 0;
                    do {
                        fos.write(buffer, 0, n);
                        n = is.read(buffer);
                    } while (n != -1);
                    fos.close();
                    handler.sendEmptyMessage(0);
                } catch (MalformedURLException e) {
                    handler.sendEmptyMessage(1);
                    e.printStackTrace();
                } catch (IOException e) {
                    handler.sendEmptyMessage(2);
                    e.printStackTrace();
                }
            }
        }).start();
    }

    final public boolean fileExists() {
        return new File(filePath).exists();
    }

    final public HashSet<View> getBindedViews() {
        return viewSet;
    }

    /**
     * 如果只设置宽或高，则返回等比例缩放的图片。如果都没设置则返回1:1的原图，如果都设置了则进行剪切缩放（如果长宽比例�?��则只进行缩放�?
     */
    final public Bitmap getBitmap() {
        return bitmap;
    }

    /**
     * @return 从缩略图中解码出Bitmap，如果不存在返回null
     * @throws IOException
     */
    final private Bitmap getBitmapFromCache() {
        Bitmap bitmap = null;
        try {
            if (new File(cacheFilePath).exists()) {
                bitmap = ImgUtil.getBitmap(cacheFilePath);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;

    }

    /**
     * @return 在Bitmap加载之前可能为0
     */
    public int getHeight() {
        return height;
    }

    public String getImagePath() {
        return this.filePath;
    }

    public ImgListener getImgListener() {
        return imgListener;
    }

    public void setImgListener(ImgListener imgListener) {
        this.imgListener = imgListener;
    }

    public String getUrl() {
        return url;
    }

    public Img setUrl(String url) {
        this.url = url;
        isSizeKnown = false;
        return this;
    }

    /**
     * @return 在Bitmap加载之前可能为0
     */
    public int getWidth() {
        return width;
    }

    public boolean isBitmapDecoded() {
        return null != bitmap && !bitmap.isRecycled();
    }

    public void recycle() {
        if (null != bitmap) {
            if (!bitmap.isRecycled()) {
                bitmap.recycle();
            }
            bitmap = null;
        }
    }

    /**
     * 生成缩略图文件缓存（如果解码原图则不产生缓存文件;如果解码后的图片和原图面积比例大于1:4，则不产生缩略图）
     */
    final private void saveCacheIfNecessary() {
        if (null == bitmap) {
            return;
        }
        //原始尺寸的图片
        if (sizeMode == SIZE_MODE_BASE_ON_ORIGIN_SIZE) {
            return;
        }
        //缓存已经存在
        File file = new File(cacheFilePath);
        if (file.exists()) {
            return;
        }
        //原始图片和目标Bitmap尺寸差距不大，没有缓存的意义
        BitmapFactory.Options options = ImgUtil.getSizeOptions(filePath);
        if (options.outHeight * options.outHeight < 4 * bitmap.getWidth() * bitmap.getHeight()) {
            return;
        }
        ImgUtil.save(bitmap, cacheFilePath);

    }

    final public void setImageViewAsync(View imageView) {
        final ImageView iv = (ImageView) imageView;
        if (isBitmapDecoded()) {
            iv.setImageBitmap(bitmap);
        } else if (fileExists()) {
            decodeBitmapAsync(new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 0) {
                        iv.setImageBitmap(bitmap);
                    }
                }
            });
        } else {
            downloadAndDecodeAsync(new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 0) {
                        iv.setImageBitmap(bitmap);
                    }
                }
            });
        }
    }

    /**
     * 调用此方法，则不能调用其他setSize()方法，生成的Bitmap将会是圆形的
     *
     * @param radius
     */
    public Img setRadius(int radius) {
        this.radius = radius;
        setSize(radius * 2, radius * 2);
        return this;
    }

    public Img setSize(int width, int height) {
        this.width = width;
        this.height = height;
        sizeMode = SIZE_MODE_BASE_ON_EXACTLY_ARGS;
        generateCachePath();
        return this;
    }

    /**
     * 缩略图的命名策略：源文件路径的哈希码
     */
    final private void generateCachePath() {
        switch (sizeMode) {
            case SIZE_MODE_BASE_ON_EXACTLY_ARGS://宽高均设定
                this.cacheFilePath = cacheDirectory.getPath() + "/" + filePath.hashCode() + '-' + width + 'x' + height;
                break;
            case SIZE_MODE_BASE_ON_HEIGHT://高度已设定，等比例缩放
                this.cacheFilePath = cacheDirectory.getPath() + "/" + filePath.hashCode() + '-' + sizeMode + '-' + height;
                break;
            case SIZE_MODE_BASE_ON_WIDTH://宽度已设定，等比例缩放
                this.cacheFilePath = cacheDirectory.getPath() + "/" + filePath.hashCode() + '-' + sizeMode + '-' + width;
                break;
            default://解码原图
                this.cacheFilePath = filePath;
                break;
        }

    }

    public Img setSize(int size) {
        setSize(size, size);
        return this;
    }

    public Img setSizeBaseOnHeight(int height) {
        this.height = height;
        sizeMode = SIZE_MODE_BASE_ON_HEIGHT;
        generateCachePath();
        return this;
    }

    public Img setSizeBaseOnWidth(int width) {
        this.width = width;
        sizeMode = SIZE_MODE_BASE_ON_WIDTH;
        generateCachePath();
        return this;
    }

    /**
     * @param srcPath 图片的绝对路径
     */
    public Img setSrc(String srcPath) {
        this.filePath = srcPath;
        isSizeKnown = false;
        return this;
    }

    final public void unbindView(View view) {
        viewSet.remove(view);
    }

}